package com.ggy.babybed.socketwork;

import android.util.Log;

import com.ggy.babybed.socketwork.command.INetworkCommand;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 * @author gonggy
 *
 */
public class NetworkCommandRunner {

    public static final String TAG = "NetworkCommadRunner";

    public static void run(INetworkCommand command) throws Exception{
        OutputStream out = null;
        InputStream in = null;
        Socket socket = null;

        try {
            Log.i(TAG, "连接网络");
            socket = NetworkFactory.createSocket();
            out = socket.getOutputStream();
            in = socket.getInputStream();

            Log.i(TAG, "发送数据");
            if(!command.write(out)){
                throw new Exception("发送数据失败");
            }
            Log.i(TAG, "接收数据");
            if(!command.read(in)){
                throw new Exception("接收数据失败");
            }
        } catch (IOException e) {
            Log.e(TAG, "连接网络失败,详细信息："+e.getMessage());
            throw e;
        } finally {
            if(null != out){
                out.close();
            }
            if(null != in){
                in.close();
            }
            if(null != socket){
                socket.close();
            }
        }
    }

    public static void run(String host, int port, int timeout, INetworkCommand command) throws Exception{
        OutputStream out = null;
        InputStream in = null;
        Socket socket = null;

        try {
            Log.i(TAG, "连接网络");
            socket = NetworkFactory.createSocket(host, port, timeout);
            out = socket.getOutputStream();
            in = socket.getInputStream();

            Log.i(TAG, "发送数据");
            if(!command.write(out)){
                throw new Exception("发送数据失败");
            }
            Log.i(TAG, "接收数据");
            if(!command.read(in)){
                throw new Exception("接收数据失败");
            }
        } catch (IOException e) {
            Log.e(TAG, "连接网络失败,详细信息："+e.getMessage());
            throw e;
        } finally {
            if(null != out){
                out.close();
            }
            if(null != in){
                in.close();
            }
            if(null != socket){
                socket.close();
            }
        }
    }

    public static void runWithAlive(String host, int port, int timeout, INetworkCommand command){
        Socket socket = null;
        OutputStream out = null;
        InputStream in = null;
        ScheduledExecutorService service = null;
        ScheduledFuture<?> future = null;
        try {
            socket = NetworkFactory.createSocket(host, port, timeout);
            out = socket.getOutputStream();
            in = socket.getInputStream();
            HeartTask task = new HeartTask(command, out, in, future);
            service = Executors.newScheduledThreadPool(1);
            future = service.scheduleWithFixedDelay(task, 5000, 5000, TimeUnit.MILLISECONDS);
            future.get();
        } catch (Exception e) {
            e.printStackTrace();
            try {
                if(null != out){
                    out.close();
                }
                if(null != socket){
                    socket.close();
                }
            } catch (IOException e2) {
                e2.printStackTrace();
            }
            try {
                System.out.println("重连中...");
                TimeUnit.MILLISECONDS.sleep(NetworkConstant.DEFAULT_WAITTIME);
                runWithAlive(host, port, timeout, command);
            } catch (InterruptedException e3) {
                e3.printStackTrace();
            }
        }

    }

}

class HeartTask implements Runnable{
    INetworkCommand command;
    OutputStream out;
    InputStream in;
    ScheduledFuture<?> future;
    public HeartTask(INetworkCommand cmd, OutputStream out, InputStream in, ScheduledFuture<?> future) {
        this.out = out;
        this.in = in;
        this.command = cmd;
        this.future = future;
    }

    @Override
    public void run() {
        try {
            command.write(out);
            command.read(in);
        } catch (IOException e) {
            e.printStackTrace();
            future.cancel(true);
        }
    }
}

